﻿using BaseUtils;
using BaseUtils.AppConfig;
using BaseUtils.Helper;
using BaseUtils.Logger;
using DatabaseCore;
using DatabaseCore.Sqlite;
using DeviceManage.PLC;
using DriveManage.Modbus;
using DriveManage.SocketClient;
using DriveManage.Tcp.Server;
using Newtonsoft.Json;
using NW_WEB_Service.App.Interface;
using NW_WEB_Service.com.app.services;
using NW_WEB_Service.com.utils;
using Service.src.Flow.Api;
using Service.src.Flow.JavaScript;
using Service.src.Flow.Server;
using Service.src.Model.Folw;
using Service.src.NW.Enum;
using Service.src.NW.Model.Drive;
using Service.src.NW.Model.Enum;
using Service.src.NW.Model.Folw;
using Service.src.NW.Processor.Core;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Threading.Tasks;

namespace Service.src.NW.Model
{
    public class AppData
    {
        public static bool AppRunSuccess = false; // APP启动成功
        //public static CancellationTokenSource AppRunSuccessTokenSource = new CancellationTokenSource(); // APP启动成功
        //public static CancellationToken AppRunSuccessV2; // APP启动成功
        public static string AppPath = AppDomain.CurrentDomain.BaseDirectory;
        public static string AllFlowFileName = "nws.db";
        public static string UserPage = "UserPage.";
        public static string UserPageComponent = "Component";
        public static string UserPageStyle = "Style";

        public readonly static string NodeHubName = "NodeHub.json";
        public readonly static string RuntimeFlowData = "projects\\";
        public readonly static string RuntimeFlowDataFlowDirectory = RuntimeFlowData + "flow\\";
        public readonly static string RuntimeFlowDataViewDirectory = RuntimeFlowData + "view\\";

        public static ConcurrentDictionary<long, FlowBaseInfo> AllFlowBaseInfos = new ConcurrentDictionary<long, FlowBaseInfo>(); // 所有流程的路径信息
        public static List<SystemEvent> AllEvents = new List<SystemEvent>();
        public static ConcurrentDictionary<long, FlowRoot> OpenFlows = new ConcurrentDictionary<long, FlowRoot>(); // 被打开或编辑的流程
        public static ConcurrentDictionary<long, FlowRoot> Runings = new ConcurrentDictionary<long, FlowRoot>(); // 正在运行的流程
        public static ConcurrentDictionary<long, ConcurrentBag<int>> RuningNodes = new ConcurrentDictionary<long, ConcurrentBag<int>>(); // 正在运行的流程节点线程

        public static List<string> IgnoreSystemTables = new List<string>() { "sqlite_sequence" };
        public static List<string> IgnoreSystemTablePrefix = new List<string>() { "sys_" };
        public static List<GlobalParamEntity> GlobalParams = new List<GlobalParamEntity>(); // 全局变量

        public static ConcurrentDictionary<long, DataSourceClient> DatabaseCache = new ConcurrentDictionary<long, DataSourceClient>();

        public static WebSocketServer _WebSocket;
        /// <summary>
        /// 是否开启监听设备
        /// 1，在软件启动后会开启，设置为true
        /// 2，在修改设备和添加新设备时会暂停监听，
        /// </summary>
        //public static bool IsEnabledDevice = false;

        /// <summary>
        /// 提前缓存所有PLC设备和地址
        /// </summary>
        public static Dictionary<int, IPLCHelper> IPLCHelpers = new Dictionary<int, IPLCHelper>();
        public static Dictionary<int, SysPlcDriverAddress> CachePLCAddressList = new Dictionary<int, SysPlcDriverAddress>();
        public static Dictionary<int, ISocketHandler> SocketHandlers = new Dictionary<int, ISocketHandler>();
        public static Dictionary<int, ModbusService> ModbusServices = new Dictionary<int, ModbusService>();

        public static void AppRunSuccessed()
        {
            if (!AppRunSuccess)
            {
                AppRunSuccess = true;
                PlcProcessor.OnPLC();
                EventProcessor.OnEvent();
                OnFlow();
            }
        }

        private static void CommonLongTimeThread()
        {
            int RefreshTime = 180;
            if (BaseService.AppConfig?.field?.Refresh > 0)
            {
                RefreshTime = BaseService.AppConfig.field.Refresh;
            }
            if (AppRunSuccess)
            {

            }
        }

        public static void OnFlow()
        {
            foreach (var item in AllFlowBaseInfos)
            {
                Task.Run(() =>
                {
                    CycleFlow(item.Value);
                });
            }
        }

        private static async void CycleFlow(FlowBaseInfo Flow)
        {
            while (Flow.EnableCycle)
            {
                Thread.Sleep(Flow.CycleTime);
                FlowServer.RunFlow(Flow.id);

                FlowBaseInfo cur = AllFlowBaseInfos[Flow.id];
                if (cur != null && !cur.EnableCycle)
                {
                    Flow.EnableCycle = false;
                }
            }
        }

        public static void TempFun()
        {
            while (true)
            {

                try
                {
                    foreach (var item in Runings)
                    {
                        FlowRoot Flow = item.Value;
                        TimeSpan TS = Flow.stopwatch.Elapsed;
                        double Time = TS.TotalSeconds;
                        if (Time > 10)
                        {
                            FlowServer.StopFlow(Flow.Id);
                        }
                    }
                }
                catch (Exception)
                {

                }
                Thread.Sleep(1000);
            }
        }

        /// <summary>
        /// 缓存所有流程
        /// </summary>
        /// <param name="nws"></param>
        public static void SetAllFlows(List<FlowBaseInfo> Flows)
        {
            //List<FlowBaseInfo> Flows = ConvertHelper.ToObject<List<FlowBaseInfo>>(nws);
            if (AllFlowBaseInfos == null)
            {
                AllFlowBaseInfos = new ConcurrentDictionary<long, FlowBaseInfo>();
            }
            foreach (FlowBaseInfo item in Flows)
            {
                AllFlowBaseInfos.TryAdd(item.id, item);
            }
        }

        static object LockObject = new object();

        public static void AddOpenFlow(FlowRoot Open)
        {
            if (!OpenFlows.ContainsKey(Open.Id))
            {
                lock (LockObject)
                {
                    OpenFlows.TryAdd(Open.Id, Open);
                }
            }
        }

        public static void RemoveOpenFlow(long FlowId)
        {
            FlowRoot folw = null;
            OpenFlows.TryRemove(FlowId, out folw);
        }

        public static FlowBaseInfo GetFlowById(long Id)
        {
            FlowBaseInfo item = AllFlowBaseInfos[Id];
            return item;
        }

        /// <summary>
        /// 更新所有plc地址
        /// </summary>
        public AppData UpdatePlcAddress()
        {

            SysPlcDriverAddressApi sysPlcDriverAddressApi = new SysPlcDriverAddressApi();
            List<SysPlcDriverAddress> all = sysPlcDriverAddressApi.Query();

            if (all?.Count > 0)
            {
                Dictionary<int, SysPlcDriverAddress> PlcAddress = all.ToDictionary(p => p.Id, p => p);
                CachePLCAddressList = PlcAddress;
            }

            return this;
        }

        /// <summary>
        /// 开启一个 webSocket 服务
        /// </summary>
        /// <returns></returns>
        public AppData OpenWebSocket()
        {
            List<string> Urls = new List<string> { "http://127.0.0.1:9631/ws/" };
            _WebSocket = new WebSocketServer(Urls);
            _WebSocket.Open();
            return this;
        }

        public static SysPlcDriverAddress GetSysPlcDriverAddress(int AddressId)
        {
            return CachePLCAddressList[AddressId];
        }

        public AppData SetGlobalParams()
        {
            AppData.GlobalParams = GetGlobalParams();
            return this;
        }

        public GlobalParamEntity GetGlobalParam(string ParamName)
        {
            GlobalParamEntity ParamEntity = GlobalParams.Where((g) => g.Name == ParamName).FirstOrDefault();
            return ParamEntity;
        }
        public GlobalParamEntity GetGlobalParam(int Id)
        {
            GlobalParamEntity ParamEntity = GlobalParams.Where((g) => g.Id == Id).FirstOrDefault();
            return ParamEntity;
        }
        public static List<GlobalParamEntity> GetGlobalParams()
        {
            return new GlobalParamService().GetGlobalParamlist() ?? new List<GlobalParamEntity>();
        }

        /// <summary>
        /// 加载 设备 PLC/扫码抢/打印机等
        /// </summary>
        /// <param name="driverInfos"></param>
        public AppData LoadDevice()
        {

            DataSourceClient defaultSqlite = new SqliteHelper().ConnectionSqlite();
            DatabaseCache.TryAdd(SqliteHelper.SystemDefaultDBID, defaultSqlite);

            SysDriverServer driverServer = new SysDriverServer();
            List<SysDevicrInfo> Devices = driverServer.GetDrivelist(SqliteHelper.SystemDefaultDBID);
            if (Devices?.Any() == true)
            {
                Devices.ForEach(Device =>
                {
                    Task.Run(() =>
                    {
                        StartDevice(Device);
                    });
                });
            }
            return this;
        }

        /// <summary>
        /// 启动设备
        /// </summary>
        /// <param name="Device"></param>
        public void StartDevice(SysDevicrInfo Device)
        {

            if (Device.DeviceType.Contains(DeviceTypeEnum.PLC.ToString()))
            {
                PlcInfo plcInfo = new PlcInfo();
                plcInfo.Ip = Device.Ip;
                plcInfo.CpuSolt = Device.Slot;
                plcInfo.Port = int.Parse(Device.Port);
                plcInfo.cpuType = Device.DeviceModel;

                IPLCHelper pLCHelper = PLCFactory.InstantiationPLC(plcInfo);
                pLCHelper.OnErrorHandler += OnPlcErrorHandler;
                IPLCHelpers[Device.Id] = pLCHelper;
            }
            if (Device.DeviceType == DeviceTypeEnum.SOCKET_CLIENT.ToString())
            {
                ISocketHandler SocketClient = new SocketClientManager(Device.Ip, int.Parse(Device.Port), Device.ReceiveTimeout, Device.SendTimeout, Device.DeviceName);
                SocketClient.OnConnected += OnConnectHandler;
                SocketClient.OnConnectError += OnConnectErrorHandler;
                SocketClient.OnFaildConnect += OnFaildConnectHandler;
                SocketClient.OnReceiveMsg += OnReceiveMsg;
                bool conn = SocketClient.Start();
                if (!conn)
                {
                    LoggerService.Error($"{Device.DeviceName}设备连接失败，,Device={Device.ToJson()}");
                }
                else
                {
                    SocketHandlers[Device.Id] = SocketClient;
                }
            }
            if (Device.DeviceType == DeviceTypeEnum.SOCKET_SERVER.ToString())
            {
                string Rerminator = JsonConvert.DeserializeObject<string>($"\"{Device.Rerminator}\"");
                ISocketHandler SocketServer = new SocketServerManager(int.Parse(Device.Port), Rerminator);

                SocketServer.OnClientConnected += OnClientConnected;
                SocketServer.OnClientDisconnected += OnClientDisconnected;
                SocketServer.OnMessageReceived += (SocketServerManager ServerManager, TcpClient client, byte[] buffer, string Message) => OnMessageReceived(Device, client, Message);
                bool conn = SocketServer.Start();
                if (!conn)
                {
                    LoggerService.Error($"{Device.DeviceName}设备启动失败，,Device={Device.ToJson()}");
                }
                else
                {
                    SocketHandlers[Device.Id] = SocketServer;
                }
            }
            if (Device.DeviceType == DeviceTypeEnum.MYSQL.ToString())
            {
                DataSourceClient Mysql = new SqliteHelper().ConnectionMysql(Device.ConnectionString);
                DatabaseCache[Device.Id] = Mysql;
            }
            if (Device.DeviceType == DeviceTypeEnum.SQLITE.ToString())
            {
                DataSourceClient Sqlite = new SqliteHelper().ConnectionSqlite(Device.ConnectionString);

                DatabaseCache[Device.Id] = Sqlite;
            }
            if (Device.DeviceType == DeviceTypeEnum.SERIAL_PORT.ToString())
            {
                ModbusService ms = new ModbusService(ModbusEnum.ModbusSerialPort, null,
                    Device.Port, Device.baudRate, Device.parity, Device.dataBits, Device.stopBits);
                ms.Open();
                ModbusServices[Device.Id] = ms;
            }
        }

        public void StartDevice(int Id)
        {
            DeviceInterface Device = new DeviceService();
            SysDevicrInfo DevicrInfo = Device.GetDeviceById(Id);
            StartDevice(DevicrInfo);
        }

        /// <summary>
        /// 服务端收到客户端消息
        /// </summary>
        /// <param name="client"></param>
        /// <param name="Message"></param>
        private void OnMessageReceived(SysDevicrInfo Device, TcpClient client, string Message)
        {
            string IpAddress = ((IPEndPoint)client.Client.RemoteEndPoint).Address.ToString();
            string REC = $"服务端收到客户端（{IpAddress}）发送的消息：{Message}";
            LoggerService.Info(REC);
            DeviceMessageResult MessageResult = new DeviceMessageResult(DeviceTypeEnum.SOCKET_SERVER, REC);
            MessageResult.Data = Message;
            MessageResult.DeiverInstance = Device;
            MessageResult.MessageStatus = DeviceMessageStatusEnum.RECEIVING_DATA;
            JavaScriptEvent.Send(JavaScriptEventEnum.DEVICE_LOGGER, MessageResult);
        }

        private void OnClientDisconnected(TcpClient client)
        {
            string IpAddress = ((IPEndPoint)client.Client.RemoteEndPoint).Address.ToString();
            string REC = $"{IpAddress}客户端断开连接";

            LoggerService.Info(REC);
            DeviceMessageResult error = new DeviceMessageResult(DeviceTypeEnum.SOCKET_SERVER, REC);
            error.MessageStatus = DeviceMessageStatusEnum.CONNECTION_DISCONNECT;
            JavaScriptEvent.Send(JavaScriptEventEnum.DEVICE_LOGGER, error);
        }

        /// <summary>
        /// 服务端收到客户端连接
        /// </summary>
        /// <param name="client"></param>
        private void OnClientConnected(TcpClient client)
        {
            string IpAddress = ((IPEndPoint)client.Client.RemoteEndPoint).Address.ToString();
            string REC = $"收到客户端({IpAddress})的连接";
            LoggerService.Info(REC);

            DeviceMessageResult error = new DeviceMessageResult(DeviceTypeEnum.SOCKET_SERVER, REC);
            error.MessageStatus = DeviceMessageStatusEnum.CONNECTION_SUCCESS;
            JavaScriptEvent.Send(JavaScriptEventEnum.DEVICE_LOGGER, error);
        }

        /// <summary>
        /// 监听PLC的异常事件
        /// </summary>
        /// <param name="PLC"></param>
        /// <param name="AddressOffset"></param>
        /// <param name="ex"></param>
        private void OnPlcErrorHandler(PLCHelper PLCInstance, string AddressOffset, Exception ex)
        {
            DeviceMessageResult Result = new DeviceMessageResult();
            Result.DeiverInstance = PLCInstance;
            Result.Type = DeviceTypeEnum.PLC;
            Result.Exce = ex;
            Result.Message = AddressOffset;
            JavaScriptEvent.Send(JavaScriptEventEnum.DEVICE_LOGGER, Result);
        }

        private void OnFaildConnectHandler(SocketClientManager scm)
        {
            LoggerService.Error($"Socket连接发生故障,正在尝试重新连接");
            scm.StartReconnect();
        }

        /// <summary>
        /// 接收的消息
        /// </summary>
        /// <param name="scm"></param>
        /// <param name="Message"></param>
        private void OnReceiveMsg(SocketClientManager scm, string Message)
        {
            scm.AddDataCache(Message);
        }

        private void OnConnectErrorHandler(SocketClientManager scm, string ErrorMessage)
        {
            LoggerService.Error($"Socket连接发生错误,正在尝试重新连接");
            scm.StartReconnect();
        }

        private void OnConnectHandler(SocketClientManager scm)
        {
            LoggerService.Info($"Socket连接成功");
        }

        /// <summary>
        /// 检查设备连接是否异常
        /// </summary>
        public AppData CheckDeviceConnection()
        {
            Task.Run(() =>
            {
                while (true)
                {
                    foreach (var item in SocketHandlers)
                    {
                        if (!item.Value.IsConnected)
                        {
                            item.Value.StartReconnect();
                        }
                    }
                    Thread.Sleep(1000);
                }
            });
            return this;
        }

        public AppData Heartbeat(bool Enable = true)
        {
            Task.Run(() =>
            {
                while (Enable)
                {
                    foreach (var item in SocketHandlers)
                    {
                        if (item.Value.IsConnected)
                        {
                            LoggerService.Info($"正在发送心跳检测");
                            item.Value.SendMessage("2");
                        }
                        else
                        {
                            // item.Value.StartReconnect();
                        }
                    }
                    Thread.Sleep(5000);
                }
            });
            return this;
        }

        /// <summary>
        /// 加载事件
        /// </summary>
        /// <exception cref="NotImplementedException"></exception>
        public AppData LoadEvent()
        {
            List<SystemEvent> events = new EventServer().SearchEvent(SqliteHelper.SystemDefaultDBID);
            AllEvents = events;
            return this;
        }

        public static void RemoveRunCompleteNodeId(long FlowId, int NodeId)
        {
            try
            {
                var sy = RuningNodes[FlowId].Where(n => n != NodeId);
                RuningNodes[FlowId] = new ConcurrentBag<int>(sy);
                LoggerService.Info($"节点执行结束，流程ID：{FlowId}，节点ID：{NodeId}");
            }
            catch (Exception ex)
            {
                LoggerService.Error($"节点执行结束失败，流程ID：{FlowId}，节点ID：{NodeId}，失败原因：{ex.Message}", ex);
            }
        }

        public static void AddRuningNodeId(long FlowId, int NodeId)
        {
            try
            {
                RuningNodes[FlowId].Add(NodeId);
            }
            catch (Exception ex)
            {
                LoggerService.Error($"添加运行节点失败，失败原因：{ex.Message}", ex);
            }
        }
    }
}
